package tool

import java.io.File
import java.nio.file.Files
import dao.ModeDao

import javax.inject.Inject
import models.Tables.UserRow
import org.apache.commons.lang3.StringUtils
import org.joda.time.DateTime
import play.api.mvc.{AnyContent, MultipartFormData, Request, RequestHeader}
import utils.{DesEncrypter, Utils}

import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
import models.Tables._
import org.slf4j.LoggerFactory
import play.api.http.HttpVerbs
import play.api.libs.json.{JsValue, Json}
import shared.{ResultData, Shared}

import scala.math.BigDecimal.RoundingMode
import tool.Pojo.PredictData
import implicits.Implicits._
import play.api.data.FormBinding
import ujson.play.PlayJson
import upickle.default._

import java.net.URLEncoder

/**
 * Created by yz on 2018/8/23
 */
class Tool @Inject()(modeDao: ModeDao) {

  def getUserName(implicit request: RequestHeader) = {
    request.session.get(Shared.userStr).get
  }

  def getTimes(times: Option[Int]) = times.map(_.toString).getOrElse("不限")

  def dataTime2String(dateTime: Option[DateTime]) = dateTime.map(_.toString("yyyy-MM-dd HH:mm:ss")).getOrElse("不限")

  def isb(user: UserRow) = user.remainTimes.map(_ > 0).getOrElse(true) && user.startTime.map(_.isBeforeNow).getOrElse(true) &&
    user.endTime.map(_.isAfterNow).getOrElse(true)

  val newPasswordDesEncrypter = new DesEncrypter("newPassword12345")

  val registerDesEncrypter = new DesEncrypter("register12345678")

  def getUserId(implicit request: RequestHeader) = {
    request.session.get(Utils.idStr).get.toInt
  }

  def createTempDirectory(prefix: String) = {
    if (isTestMode) Utils.testDir else Files.createTempDirectory(prefix).toFile
  }

  def isTestMode = {
    val mode = Utils.execFuture(modeDao.select)
    if (mode.test == "t") true else false
  }

  def deleteDirectory(direcotry: File) = {
    if (!isTestMode) Utils.deleteDirectory(direcotry)
  }

  def getPredictValue(file: File): Map[String, String] = {
    val lines = Utils.file2Lines(file)
    getPredictValue(lines)
  }

  def getPredictValue(lines: mutable.Buffer[String]): Map[String, String] = {
    val headers = lines.head.split("\t")
    headers.zip(lines(1).split("\t")).toMap
  }

  def getMissionIdDirById(missionId: Int)(implicit request: RequestHeader) = {
    val userMissionFile = getUserMissionDir
    new File(userMissionFile, missionId.toString)
  }

  def getUserMissionDir(implicit request: RequestHeader) = {
    val userIdDir = getUserIdDir
    new File(userIdDir, "mission")
  }

  def getUserIdDir(userId: Int) = {
    new File(Utils.userDir, userId.toString)
  }

  def getUserIdDir(implicit request: RequestHeader) = {
    val userId = getUserId
    new File(Utils.userDir, userId.toString)
  }

  def getResultData(file: File) = {
    val map = getPredictValue(file)
    ResultData(cirrhosis = BigDecimal(map("Cirrhosis")), lateFibrosis = BigDecimal(map("Late_Fibrosis")),
      result = map("results"))
  }

  def getMissionJson(row: MissionRow, resultData: ResultData) = {
    val missionMap = Utils.getMapByT(row)
    Json.toJson(missionMap)
  }

  def getOrinalData(lines: mutable.Buffer[String]) = {
    val map = getPredictValue(lines)
    OrignalData(map("SampleID"), map("Age"), map("AST"), map("ALT"),
      map("PLT"))
  }

  def getResultData(lines: mutable.Buffer[String]) = {
    val map = getPredictValue(lines)
    ResultData(cirrhosis = BigDecimal(map("Cirrhosis")), lateFibrosis = BigDecimal(map("Late_Fibrosis")),
      result = map("results"))
  }

  def getExtraData(file: File) = {
    val map = getPredictValue(file)
    ExtraDataF(getValue(map, "送检单位"), getValue(map, "地址"), getValue(map, "姓名"), getValue(map, "性别"),
      getValue(map, "送检科室"), getValue(map, "申请医生"), getValue(map, "门诊/住院号"), getValue(map, "采样时间"),
      getValue(map, "送检时间"), getValue(map, "样本类型"), getValue(map, "样本状态"),
      getValue(map, "标题"), getValue(map, "检验人"), getValue(map, "审核人"), getValue(map, "检验日期"),
      getValue(map, "报告日期")
    )
  }

  def getValue(map: Map[String, String], header: String) = {
    val str = map.getOrElse(header, "NA")
    if (str == "NA") "" else str
  }


  def getEmptyExtraDataRow(id: Int, userId: Int) = {
    ExtraDataRow(id, userId, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "")
  }


}

object Tool{
  val logger = LoggerFactory.getLogger(this.getClass)
  def dataCheck(data: PredictData) = {
    PredictDataValidTool.valid(data)
  }

  def jsonParse(jsValue: JsValue) =
    FormUtils.fromJson(jsValue, Form.FromJsonMaxChars).mapValues(Seq(_))

  def multipartFormParse(body: MultipartFormData[_]) = body.asFormUrlEncoded

  def transformRq(implicit
                  request: Request[AnyContent],
                  formBinding: FormBinding
                 ) = {

    val unwrap = request.body match {
      case body: play.api.mvc.AnyContent =>
        body.asFormUrlEncoded
          .orElse(body.asMultipartFormData)
          .orElse(body.asJson)
          .getOrElse(body)
      case body => body
    }
    unwrap match {
      case body: play.api.libs.json.JsValue =>
        PlayJson.transform(body, reader[ujson.Value])
      case x =>
        val data: Map[String, Seq[String]] = unwrap match {
          case body: Map[_, _] => body.asInstanceOf[Map[String, Seq[String]]]
          case body: MultipartFormData[_] => multipartFormParse(body)
          case Right(body: MultipartFormData[_]) => multipartFormParse(body)
          case _ => Map.empty
        }
        val method: Map[_ <: String, Seq[String]] = request.method.toUpperCase match {
          case HttpVerbs.POST | HttpVerbs.PUT | HttpVerbs.PATCH => Map.empty
          case _ => request.queryString
        }
        val map = (data ++ method).foldLeft(Map.empty[String, String]) {
          case (s, (key, values)) =>
            if (key.endsWith("[]")) {
              val k = key.dropRight(2)
              s ++ values.zipWithIndex.map { case (v, i) => s"$k[$i]" -> v }
            } else {
              s + (key -> values.headOption.getOrElse(""))
            }
        }
        logger.info(s"${map}")
        writeJs(map)
    }
  }


  def getUserId(implicit request: RequestHeader) = {
    request.session.get(Utils.idStr).get.toInt
  }

  def urlEncode(url: String) = {
    URLEncoder.encode(url, "UTF-8")
  }

  def getContentDisposition(url: String) = {
    val encodeUrl = Tool.urlEncode(url)
    s"attachment; filename*=utf-8''${encodeUrl}"
  }

}
